package main

import "fmt"

func main() {
	a := 10
	str := "abc"

	func() {
		a = 666
		str = "go"
		fmt.Printf("闭包的内部: a = %d, str = %s\n", a, str)
	}()

	fmt.Printf("闭包的内部: a = %d, str = %s\n", a, str)

	/*
	输出结果:
	闭包的内部: a = 666, str = go
	闭包的内部: a = 666, str = go
	说明: 闭包func改了外部变量的值后, 后边也就跟着改变了, 闭包是以引用方式捕获外部变量
	 */


	fmt.Println(test01())
	fmt.Println(test01())
	fmt.Println(test01())
	fmt.Println(test01())

	/*
	输出结果:
	1
	1
	1
	1
	说明: test01中, 只有该函数被调用后, 这个 x 才会被分配空间和被初始化
	 */


	f := test02()
	fmt.Println("f = ", f()) // 名每次都调用该函数
	fmt.Println("f = ", f())
	fmt.Println("f = ", f())
	fmt.Println("f = ", f())
	/*
	输出结果:
	f =  1
	f =  4
	f =  9
	f =  16
	说明: 它不关心这些捕获的变量和常量是否已经超出了作用域, 所以只有闭包还在使用它, 这些变量就还会存在
	 */
}


func test01() int {
	var x int // m有初始化, 值为0
	x++
	return x * x // 函数调用完毕, x 会自动释放
}

// 函数的返回类型是一个匿名函数, 返回一个函数类型
func test02() func() int {
	var x int
	return func() int { // 返回一个函数类型, 闭包
		x++
		return x * x
	}
}